import * as log4js from "log4js";
import { Logger } from "log4js";
import * as os from 'os'
import * as path from 'path'
import * as util from 'util'
import { apiclientWrapper } from "./apiclientWrapper";
import * as url from "url";
const config_path = path.resolve('./config/log4js.json')
console.log('configure log4js config_path', config_path)
const config = require(config_path);
// console.log('configure log4js', config)

log4js.configure(config)

export interface LogService {
    Error(message: string): void;
    Error(error: Error | object): void;
    Error(message: string, error: Error | object): void;
    Error(message: string, error: Error, info: object): void;

    Info(message: string, info: object): void;
    Info(message: string): void;
    Info(info: object): void;

    Debug(message: string, info: object): void;
    Debug(message: string): void;
    Debug(info: object): void;
}

export class LogServiceImpl implements LogService {

    private static LoggerCache: Map<string, LogService> = new Map<string, LogService>()
    public static GetLogger(logger?: string): LogService {
        var loggerName = logger || ''
        if (!LogServiceImpl.LoggerCache.has(loggerName)) {
            LogServiceImpl.LoggerCache.set(loggerName, new LogServiceImpl(loggerName))
        }
        return <LogService>LogServiceImpl.LoggerCache.get(loggerName)
    }
    private constructor(loggerName: string) {
        this.LoggerName = loggerName
    }
    public LoggerName: string

    public Error(message: string): void;
    public Error(error: Error | object): void;
    public Error(message: string, error: Error | object): void;
    public Error(message: string, error: Error, info: object): void;
    public Error(): void {
        // var message = this.GetMessageByArguments.apply(this, arguments)
        this.GetLogger('error').error(this.GetMessageByArguments('error', arguments))
    }

    public Info(message: string, info: object): void;
    public Info(message: string): void;
    public Info(info: object): void;
    public Info(): void {
        this.GetLogger('info').info(this.GetMessageByArguments('info', arguments))
    }

    public Debug(message: string, info: object): void;
    public Debug(message: string): void;
    public Debug(info: object): void;
    public Debug(): void {
        this.GetLogger('debug').debug(this.GetMessageByArguments('debug', arguments))
    }

    private GetLogger(level: string): Logger {
        //loggername-level
        //loggername
        //level
        var loggerName = '';
        if (config.categories[this.LoggerName + "-" + level])
            loggerName = this.LoggerName + "-" + level
        else if (config.categories[this.LoggerName])
            loggerName = this.LoggerName;
        else if (config.categories[level])
            loggerName = level;

        return log4js.getLogger(loggerName)
    }
    private GetMessageByArguments(level: string, args: IArguments) {
        //args:[message,err,info]
        //{timestamp:'2018/08/14 10:43:40.257',logLevel,categoryName,message,exception,app,appname,uid,utid,clientIp,realIp,localIp,tid,stid,depth,scope}
        var date = new Date();
        var time = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}.${date.getMilliseconds()}`
      
        var log: any = {};
        log.timestamp = time;
        log.logLevel = level;
        log.categoryName = this.LoggerName;
        
        var argsStartIndex = 0;
        if (typeof args[0] === 'string') {
            log.message = args[0];
            argsStartIndex = 1;
        }
        
        log.app = apiclientWrapper.getRequestHost();
        log.apiName = apiclientWrapper.getRequestUrl();
        log.uid = apiclientWrapper.getuid();
        log.utid = apiclientWrapper.getutid();
        log.clientIp = apiclientWrapper.getClentIp();
        log.realIp = apiclientWrapper.getRealIp();
        log.localIp = apiclientWrapper.getLocalIp();
        log.tid = apiclientWrapper.getTraceId();
        log.stid = apiclientWrapper.getstid();
        log.depth = apiclientWrapper.getDepth();
        log.accesstoken = apiclientWrapper.getAccessToken();

        

        for (let index = argsStartIndex; index < args.length; index++) {
            const element = args[index];
            var info = [];
            if (element instanceof Error) {
                log.exception = util.format(element)
            } else {
                info.push(element);
            }
            log.extend = info.length == 1 ? info[0] : info
        }
        return JSON.stringify(log);

        // str += os.EOL
    }
}

